package com.cauli.netdisk.module.config.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cauli.netdisk.base.exception.MyException;
import com.cauli.netdisk.base.utils.EnumConvertUtils;
import com.cauli.netdisk.module.config.mapper.ConfigMapper;
import com.cauli.netdisk.module.config.model.dto.ConfigAddDTO;
import com.cauli.netdisk.module.config.model.dto.ConfigDTO;
import com.cauli.netdisk.module.config.model.dto.ConfigQueryDTO;
import com.cauli.netdisk.module.config.model.dto.ConfigUpdateDTO;
import com.cauli.netdisk.module.config.model.dto.ConfigUpdateStatusDTO;
import com.cauli.netdisk.module.config.model.entity.Config;
import com.cauli.netdisk.module.config.service.ConfigService;
import com.cauli.netdisk.module.login.model.enums.LoginVerifyModeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import static com.cauli.netdisk.module.config.service.impl.ConfigServiceImpl.CACHE_NAME;

/**
 * @author Cauli
 * @date 2022-12-14 17:01:10
 * @description 系统设置属性表 服务实现类
 */
@Slf4j
@Service
@CacheConfig(cacheNames = CACHE_NAME)
public class ConfigServiceImpl extends ServiceImpl<ConfigMapper, Config> implements ConfigService {
    public static final String CACHE_NAME = "config";

    private static final String DEFAULT_USERNAME = "admin";

    private static final String DEFAULT_PASSWORD = "123456";

    private static final LoginVerifyModeEnum DEFAULT_LOGIN_VERIFY_MODE = LoginVerifyModeEnum.IMG_VERIFY_MODE;
    @Autowired
    private ConfigMapper configMapper;

    @Override
    public Page<Config> getConfigPage(ConfigQueryDTO configQueryDTO) {
        return baseMapper.selectPage(configQueryDTO.toPage(), configQueryDTO.toLambdaQueryWrapper());
    }

    @Override
    public ConfigDTO getConfigById(Long configId) {
        if (configId == null) {
            return null;
        }
        Config config = baseMapper.selectById(configId);
        ConfigDTO configDTO = new ConfigDTO();
        if (config != null) {
            BeanUtils.copyProperties(config, configDTO);
        }
        return configDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addConfig(ConfigAddDTO configAddDTO) {
        Config config = new Config();
        BeanUtil.copyProperties(configAddDTO, config);
        if (config.getConfigName() == null) {
            throw new MyException("config名为空");
        }

        // 检测config名是否被占用
        this.checkIsDuplicated(configAddDTO.getConfigName());

        baseMapper.insert(config);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfig(ConfigUpdateDTO configUpdateDTO) {
        // 根据configID获取config信息
        Config config = baseMapper.selectById(configUpdateDTO.getConfigId());
        BeanUtil.copyProperties(configUpdateDTO, config);
        if (config == null) {
            throw new MyException("config不存在");
        }

        // 检测config名是否重复
        if (configUpdateDTO.getConfigName() != null && !config.getConfigName().equals(configUpdateDTO.getConfigName())) {
            this.checkIsDuplicated(configUpdateDTO.getConfigName());
        }

        baseMapper.updateById(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeConfigStatus(ConfigUpdateStatusDTO configUpdateStatusDTO) {
        // 根据configID获取config信息
        Config config = baseMapper.selectById(configUpdateStatusDTO.getConfigId());
        if (config == null) {
            throw new MyException("config不存在");
        }
        BeanUtil.copyProperties(configUpdateStatusDTO, config);
        baseMapper.updateById(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteConfig(List<Long> configIds) {
        for (Long configId : configIds) {
            // 根据configID获取config信息
            Config config = baseMapper.selectById(configId);
            baseMapper.deleteById(config);
        }
    }

    /**
     * 检测config名是否被占用
     *
     * @param name
     */
    private void checkIsDuplicated(String name) {
        if (baseMapper.exists(new LambdaQueryWrapper<Config>().eq(Config::getConfigName, name))) {
            throw new MyException("该config名已被占用");
        }
    }

    @Cacheable(cacheNames = "config" , key = "'dto'")
    public ConfigDTO getConfig() {
        ConfigDTO configDTO = new ConfigDTO();
        List<Config> configList = configMapper.findAll();

        for (Config config : configList) {
            String key = config.getConfigName();
            try {
                Field field = ConfigDTO.class.getDeclaredField(key);
                field.setAccessible(true);
                Class<?> fieldType = field.getType();
                String configValue = config.getConfigValue();

                Object convertVal;
                if (EnumUtil.isEnum(fieldType)) {
                    convertVal = EnumConvertUtils.convertStrToEnum(fieldType, configValue);
                } else {
                    convertVal = Convert.convert(fieldType, configValue);
                }
                field.set(configDTO, convertVal);
            } catch (NoSuchFieldException | IllegalAccessException | ConvertException e) {
                log.error("通过反射, 将字段 {} 注入configDTO时出现异常：" , key, e);
            }
        }
        return configDTO;
    }

    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(allEntries = true)
    public void updateConfig(ConfigDTO configDTO) {
        List<Config> configList = new ArrayList<>();

        Field[] fields = ConfigDTO.class.getDeclaredFields();
        for (Field field : fields) {
            String key = field.getName();
            Config config = configMapper.findByName(key);
            if (config != null) {
                field.setAccessible(true);
                Object val = null;

                try {
                    val = field.get(configDTO);
                } catch (IllegalAccessException e) {
                    log.error("通过反射，从ConfigDTO获取字段 {} 时出现异常：" , key, e);
                }

                if (val != null) {
                    // 如果是枚举类型, 则取value值
                    if (EnumUtil.isEnum(val)) {
                        val = EnumConvertUtils.convertEnumToStr(val);
                    }
                    config.setConfigValue(Convert.toStr(val));
                    configList.add(config);
                }
            }
        }
        configList.forEach(config -> configMapper.updateById(config));
    }
}




